#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <functional>
#include "Log.hpp"
using namespace LogModule;

class udpserver
{
    using func_t = function<string(string)>;

public:
    udpserver(uint16_t port, func_t func)
        // : _addr(inet_addr(addr.c_str())), // 注：直接将其转换为合法的ip地址
        : _port(port),
          _func(func)
    {
        _running = false;
    }

    // 初始化：1.创建套接字 2.填充并绑定地址信息
    void Init()
    {
        // 1.创建套接字
        // 返回套接字描述符 地址族 数据类型 传输协议
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "创建套接字失败！";
            exit(1);
        }
        LOG(LogLevel::INFO) << "创建套接字";

        // 2.绑定信息
        // 2.1填充信息
        struct sockaddr_in local;
        // 将指定内存块的所有字节清零
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET; // IPv4地址族
        // local.sin_addr.s_addr = _addr;   //IP地址(主机序列转化为网络序列)
        local.sin_addr.s_addr = INADDR_ANY; // 赋值为INADDR_ANY，表示任意地址
        local.sin_port = htons(_port);      // 端口号

        // 2.2绑定信息
        int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "绑定失败";
            exit(1);
        }
        LOG(LogLevel::INFO) << "绑定成功";
    }

    // 启动运行：一直运行不停止；1.接收客户端的信息 2.对客户端发送来的信息进行回显
    void Start()
    {
        // 一定是死循环
        _running = true;
        while (_running)
        {
            // 接收客户端的信息
            char buff[1024];
            struct sockaddr_in peer;
            unsigned int len = sizeof(peer);
            // 套接字描述符，数据存放的缓冲区，接收方式：默认，保存发送方的ip与端口，输入输出参数：输入peer的大小，输出实际读取的数据大小
            ssize_t s = recvfrom(_sockfd, buff, sizeof(buff) - 1, 0, (struct sockaddr *)&peer, &len);
            buff[s] = 0;
            printf("%s\n", buff);

            // 回显消息
            if (s > 0)
            {
                // 调用自定义方法
                std::string ss = _func(string(buff));

                // 将数据发送给客户端
                // 套接字描述符，要发送的信息，发送方式：默认，接收方的ip与端口信息
                ssize_t t = sendto(_sockfd, ss.c_str(), ss.size(), 0, (struct sockaddr *)&peer, len);
                if (t < 0)
                {
                    LOG(LogLevel::WARNING) << "信息发送给客户端失败";
                }
            }
            memset(&buff, 0, sizeof(buff)); // 清理缓存
        }
    }

private:
    int _sockfd;
    uint32_t _addr;
    uint16_t _port;
    bool _running;

    // 回调方法
    func_t _func;
};